package com.lavegue.common;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.SimpleExpression;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public abstract class BaseHibernateDao<T, PK extends Serializable>  extends HibernateDaoSupport implements BaseDao<T, PK> {
	
	protected Class entityClass;
	public Class getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class entityClass) {
		this.entityClass = entityClass;
	}
	
	public BaseHibernateDao(Class entityClass) {
		this.entityClass = entityClass;
	}
	
	public void delete(T obj) {
		 this.getHibernateTemplate().delete(obj);
	}

	public void deleteById(PK id) {
		 Object obj = this.getHibernateTemplate().get(this.entityClass, id);
		 this.getHibernateTemplate().clear();
		 if (obj != null) {
			 this.getHibernateTemplate().delete(obj);
		 }
	}

	public List<T> findAll() {
		return this.getHibernateTemplate().find("from " + this.entityClass.getName());
	}

	public T findById(PK id) {
		return (T) this.getHibernateTemplate().get(entityClass, id);
	}

	
	public int getTotal() {
		String sql = "select count(*) from " + this.entityClass.getName();
		List list = this.getHibernateTemplate().find(sql);
		return Integer.valueOf(list.get(0) + "");
	}
	
	public int getTotal(final List<Criterion> conditions) {
		return (Integer) this.getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(entityClass);
				if (conditions != null) {
					for (Criterion c : conditions) {
						criteria.add(c);
					}
				}
				criteria.setProjection(Projections.rowCount()).uniqueResult();
				return criteria.uniqueResult();
			}
		});
	}
	
	public void save(T obj) {
		this.getHibernateTemplate().save(obj);
	}

	public int getTotal(String hql, Object[] params) {
		List list = this.getHibernateTemplate().find("select count(*) " + hql, params);
		return Integer.valueOf(list.get(0).toString());
	}
	
	public void update(T obj) {
		this.getHibernateTemplate().update(obj);
	}
	
	public Page<T> findPage(final int pageNo, final int pageSize) {
		
		List<T> list= (List<T>) this.getHibernateTemplate().execute(new HibernateCallback() {
			
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(entityClass);
				
				criteria.setFirstResult(computeStart(pageNo, pageSize));
				criteria.setMaxResults(pageSize);
				return criteria.list();
			}
		});
		int total = this.getTotal();
		Page<T> page = new Page<T>(pageNo, total, list, pageSize);
		return page;
	}
	
	
	@SuppressWarnings("unchecked")
	public Page<T> findPage(final int pageNo, final int pageSize, final List<Criterion> conditions, final Order order) {
		final int total = this.getTotal(conditions);
		final int totalPage = countPage(total, pageSize);
		List<T> list= (List<T>) this.getHibernateTemplate().execute(new HibernateCallback() {
			
			public Object doInHibernate(Session session) throws HibernateException,
					SQLException {
				Criteria criteria = session.createCriteria(entityClass);
				if (conditions != null) {
					for (Criterion c : conditions) {
						criteria.add(c);
					}
				}
				if (order != null) {
					criteria.addOrder(order);
				}
				//如果页数大于总页数，则取最后一页
				if (pageNo > totalPage) {
					criteria.setFirstResult(computeStart(totalPage, pageSize));
				} else {
					criteria.setFirstResult(computeStart(pageNo, pageSize));
				}
				criteria.setMaxResults(pageSize);
				return criteria.list();
			}
		});
		////如果页数大于总页数，则取最后一页
		int pageNoNew = (pageNo > totalPage)?  totalPage: pageNo;
		Page<T> page = new Page<T>(pageNoNew, total, list, pageSize);
		return page;
	}
	
	protected int computeStart(int pageNo, int pageSize) {
		return (pageNo - 1) * pageSize;
	}
	
	/**
	 * 计算总页数
	 * @param totalRecord
	 * @param pageSize
	 * @return
	 */
	protected int countPage(int totalRecord, int pageSize) {
		if (totalRecord % pageSize == 0) {
			return totalRecord/pageSize;
		} else {
			return totalRecord/pageSize + 1;
		}
	}

}
